package com.ld.security.common.mybatis.core.wrapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ld.security.common.core.constant.CSuperConstant;
import com.ld.security.common.core.util.GenericUtil;
import com.ld.security.common.mybatis.anno.SqlKey;
import com.ld.security.common.mybatis.anno.SqlKeys;
import com.ld.security.common.core.base.column.ListString;
import com.ld.security.common.core.base.column.SuperColumn;
import com.ld.security.common.core.base.po.SuperPo;
import com.ld.security.common.mybatis.constant.SqlCondition;
import com.ld.security.common.core.exception.ApiException;
import com.ld.security.common.core.util.ReflectionUtil;
import com.ld.security.common.core.util.TemplateUtil;
import com.ld.security.common.mybatis.base.constant.SuperConstant;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

public class EntityWrapper<E> extends QueryWrapper<E> {

    public EntityWrapper() {
    }

   private static List<SqlCondition> sqlConditionList =  Arrays.asList(SqlCondition.eq,SqlCondition.like,SqlCondition.like_left,SqlCondition.like_right);

    /**
     * 根据列明构造条件
     *
     * @param columnName
     * @param condition
     * @param val
     * @return
     */
    private static  <E> void addColumn(QueryWrapper<E> qw ,String columnName, SqlCondition condition, Object val) {
        //值预处理
        if (val == null) {
            return ;
        } else if (val instanceof  String) {
            if (TemplateUtil.isNull((String) val)) {
                return ;
            }
        } else if(sqlConditionList.contains(condition)){
               if (val instanceof SuperColumn) {
                    SuperColumn sc = (SuperColumn) val;
                    val = sc.getValue();
                    if (((String) val).length() == 0) {
                        return ;
                    }
                }
        } else if (val instanceof SuperConstant.SuperEnum) {
            SuperConstant.SuperEnum se = (SuperConstant.SuperEnum) val;
            val = se.getValue();
        }
       else if(val instanceof Collection){
            Collection col = (Collection)val;
            if(col.isEmpty()){
                return;
            }
            for (Object o : col) {
                if(o instanceof  CSuperConstant.EnSuperEnum){
                    Collection< CSuperConstant.EnSuperEnum> cols = col;
                    val = cols.stream().map(v -> v.getValue()).collect(Collectors.toList());
                    //获取第一个元素，停止
                    break;
                }

            }
        }


        switch (condition) {
            case eq: {
                qw.eq(columnName, val);
                break;
            }
            case ne: {
                qw.ne(columnName, val);
                break;
            }
            case gt: {
                qw.gt(columnName, val);
                break;
            }
            case ge: {
                qw.ge(columnName, val);
                break;
            }
            case lt: {
                qw.lt(columnName, val);
                break;
            }
            case le: {
                qw.le(columnName, val);
                break;
            }
            case like: {
                qw.like(columnName, val.toString());
                break;
            }
            case like_left: {
                qw.likeLeft(columnName, val.toString());
                break;
            }
            case like_right: {
                qw.likeRight(columnName, val.toString());
                break;
            }
            case like_many:{
                Collection collection =(Collection)  val;
                for (Object v : collection) {
                        qw.or();
                        qw.like(columnName,v);

                }
                break;
            }
            case in: {

                    qw.in(columnName, (Collection<?>) val);


                break;
            }
            case between: {
                //区间查询
                if(val instanceof String){
                    String str = val.toString();
                    String[] keys = str.split("-");
                    qw.between(columnName, keys[0], keys[1]);
                }else if(val instanceof List){
                    List keys = (List)val;
                    qw.between(columnName, keys.get(0), keys.get(1));
                }else{
                    ApiException.throw400("异常用法in语法");
                }

                break;
            }

        }

    }

    /**
     * 根据属性名构造条件
     *
     * @param fieldName
     * @param condition
     * @param val
     * @return
     */
    public EntityWrapper<E> addField(String fieldName, SqlCondition condition, Object val) {
        String columnName = TemplateUtil.javaToColumn(fieldName);
         addColumn(this,columnName, condition, val);
         return this;
    }

    private static <E> void addField(QueryWrapper<E> qw, Object query, String fieldName, SqlKey sqlKey) {
        Object val = ReflectionUtil.invokeGetter(query,fieldName);
        String columnName = "";
        if (val == null) {
            return ;
        }
        SqlCondition condition = SqlCondition.eq;
        if (sqlKey != null) {
            condition = sqlKey.value();
            columnName = sqlKey.name();
        }

        if(TemplateUtil.isNull(columnName)){
            columnName = fieldName;
        }


        columnName = TemplateUtil.javaToColumn(columnName);


        if(sqlKey.and()){

        }else{
            qw.or();
        }
         addColumn(qw,columnName,condition,val);


    }

    public static boolean isEmpty(Object po){
        if(po == null){
            return true;
        }
        for (Field field : ReflectionUtil.getAllDeclaredFields(po.getClass())) {
            SqlKey sqlKey = AnnotationUtils.findAnnotation(field,SqlKey.class);
            SqlKeys sqlKeys = AnnotationUtils.findAnnotation(field,SqlKeys.class);
            if(sqlKey != null || sqlKeys != null){
                Object val = ReflectionUtil.invokeGetter(po,field.getName());
                if(val instanceof String){
                    if(!TemplateUtil.isNull(val.toString())){
                        return false;
                    }
                }else if(val instanceof Collection){
                    Collection collection =(Collection) val;
                    if(!collection.isEmpty()){
                        return false;
                    }
                }
                else if(val != null){
                    return false;
                }
            }
        }
        return true;
    }

    public static <E> EntityWrapper<E> newInstance(){
        return new EntityWrapper<>();
    }


private static <E> void initWhere(QueryWrapper<E> qw, Object query) {


        Class clazz = query.getClass();
        List<Field> fields =  ReflectionUtil.getAllDeclaredFields(clazz);

        List<Item> items =  new LinkedList<>();

    for (Field field :fields) {
        SqlKey sqlKey = field.getAnnotation(SqlKey.class);
        SqlKeys sqlKeys = field.getAnnotation(SqlKeys.class);
        if(sqlKey == null && sqlKeys == null){
            continue;
        }
        Object val =  ReflectionUtil.invokeGetter(query,field.getName());
        if(val == null){
            continue;
        }
        if(sqlKey != null){
            items.add(new Item(sqlKey,field.getName(),val));
        }else if(sqlKeys != null){
            for (SqlKey key : sqlKeys.value()) {
                items.add(new Item(key,field.getName(),val));
            }
        }
    }
    Map<Integer,List<Item>> map= items.stream().collect(Collectors.groupingBy(val -> val.sqlKey.index()));
    map.forEach((x,ys) -> {
        for (Item y : ys) {
            if(y.value instanceof SuperPo){
                boolean b = isEmpty(y.value);
                if(b){
                    continue;
                }
                SqlKey sqlKey = y.sqlKey;
                if(sqlKey.and()){
                    qw.and((i) -> {
                        initWhere(i,y.value);
                        return i;
                    });
                }else{
                    qw.or((i) -> {
                        initWhere(i,y.value);
                        return i;
                    });
                }
            }else{
                addField(qw,query,y.fieldName, y.sqlKey);
            }
        }
    });



    }

    public EntityWrapper<E> initWhere(Object query){
        if(!isEmpty(query)){
            initWhere(this,query);
        }
        return  this;
    }

    public static<E> EntityWrapper<E> of(SuperPo query){
        EntityWrapper ew =   new EntityWrapper<>();
        ew.initWhere(query);
        return  ew;
    }


    private static class Item{
        SqlKey sqlKey;
        String fieldName;
        Object value;

        public Item(SqlKey sqlKey, String fieldName,Object value) {
            this.sqlKey = sqlKey;
            this.fieldName = fieldName;

            this.value = value;
        }
    }
}